package git.soulbgm.utils;

import lombok.extern.slf4j.Slf4j;
import okhttp3.*;

import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @author SoulBGM
 * @version 1.0
 * @date 2019/7/4 13:45
 */
@Slf4j
public class OkHttpUtil {

    private static final Map<String, Object> PARAMS = null;

    /**
     * 将参数添加到RequestBody中
     *
     * @param params 参数
     * @return 添加好参数的RequestBody
     */
    public static RequestBody getRequestBody(Map<String, Object> params) {
        FormBody.Builder builder = new FormBody.Builder();
        if (params != null) {
            Set<String> keySet = params.keySet();
            for (String key : keySet) {
                Object obj = params.get(key);
                builder.add(key, String.valueOf(obj == null ? "" : obj));
            }
        }
        return builder.build();
    }

    /**
     * 仅限GET请求
     * 参数拼接
     *
     * @param params 参数
     * @return ?key=val&key=val 格式的字符串
     */
    public static String paramsJoin(Map<String, Object> params) {
        StringBuilder pathParams = new StringBuilder();
        if (params != null) {
            pathParams.append("?");
            Set<String> keySet = params.keySet();
            for (String key : keySet) {
                Object obj = params.get(key);
                pathParams.append(key);
                pathParams.append("=");
                pathParams.append(String.valueOf(obj == null ? "" : obj));
                pathParams.append("&");
            }
            pathParams.deleteCharAt(pathParams.length() - 1);
        }
        return pathParams.toString();
    }

    /**
     * 同步获取http访问结果
     *
     * @param call Call对象
     * @return http访问返回的结果
     */
    public static byte[] getResult(Call call) {
        try {
            Response response = call.execute();
            ResponseBody body = response.body();
            return body != null ? body.bytes() : new byte[0];
        } catch (IOException e) {
            log.error("请求{}出现异常", call.request().url().toString(), e);
            return new byte[0];
        }
    }

    /**
     * 非空检验
     *
     * @param object  对象
     * @param message 如果为空报的异常信息
     */
    private static void notNull(Object object, String message) {
        if (message == null) {
            message = "No Object specified";
        }
        if (object == null) {
            throw new IllegalArgumentException(message);
        }
    }

    /**
     * 内容转实体
     *
     * @param url   地址
     * @param clazz 实体类的Class
     * @param json  Json字符
     * @return 实体类
     */
    private static <T> T bodyToModel(String url, Class<T> clazz, String json) {
        if (json == null) {
            return null;
        }
        boolean flag1 = json.startsWith("{") && json.endsWith("}");
        boolean flag2 = json.startsWith("[") && json.endsWith("]");
        if (flag1 || flag2) {
            return JsonUtil.parse(json, clazz);
        } else {
            log.error("地址 {} 返回的数据不是JSON数据", url);
            return null;
        }
    }

    /**
     * 获得OkHttpClient对象
     * 通过url判断是https请求还是http请求
     *
     * @param url 地址
     * @return OkHttpClient对象
     */
    public static OkHttpClient getOkHttpClient(String url) {
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        OkHttpClient okHttpClient = null;
        if (url.startsWith("https")) {
            okHttpClient = builder
                    .readTimeout(5, TimeUnit.SECONDS)
                    .writeTimeout(5, TimeUnit.SECONDS)
                    .connectTimeout(5, TimeUnit.SECONDS)
                    .sslSocketFactory(SSLSocketClient.getSSLSocketFactory())
                    .hostnameVerifier(SSLSocketClient.getHostnameVerifier())
                    .build();
        } else {
            okHttpClient = builder.build();
        }
        return okHttpClient;
    }

    /**
     * 同步get请求
     *
     * @param url    地址
     * @param params 参数
     * @return http访问返回的结果
     */
    public static String get(String url, Map<String, Object> params) {
        return new String(getByte(url, params));
    }

    /**
     * 同步get请求
     *
     * @param url    地址
     * @param params 参数
     * @return http访问返回的结果
     */
    public static byte[] getByte(String url, Map<String, Object> params) {
        OkHttpClient okHttpClient = getOkHttpClient(url);

        url = url + paramsJoin(params);
        Request request = new Request.Builder()
                .url(url)
                .get()
                .build();
        Call call = okHttpClient.newCall(request);
        return getResult(call);
    }

    /**
     * 同步get请求
     *
     * @param url 地址
     * @return http访问返回的结果
     */
    public static String get(String url) {
        return get(url, PARAMS);
    }

    /**
     * 同步get请求
     *
     * @param url 地址
     * @return http访问返回的结果
     */
    public static byte[] getByte(String url) {
        return getByte(url, PARAMS);
    }

    /**
     * 同步get请求
     *
     * @param url    地址
     * @param params 参数
     * @param clazz  反序列化的Class
     * @return http访问返回的如果是JSON数据则直接反序列化成该class的类
     */
    public static <T> T get(String url, Map<String, Object> params, Class<T> clazz) {
        return bodyToModel(url, clazz, get(url, params));
    }

    /**
     * 同步get请求
     *
     * @param url   地址
     * @param clazz 反序列化的Class
     * @return http访问返回的如果是JSON数据则直接反序列化成该class的类
     */
    public static <T> T get(String url, Class<T> clazz) {
        return get(url, PARAMS, clazz);
    }

    /**
     * 异步get请求
     *
     * @param url      地址
     * @param params   参数
     * @param callback Callback回调对象
     */
    public static void get(String url, Map<String, Object> params, Callback callback) {
        notNull(callback, "No Callback specified");
        OkHttpClient okHttpClient = getOkHttpClient(url);
        url = url + paramsJoin(params);
        Request request = new Request.Builder()
                .url(url)
                .get()
                .build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(callback);
    }

    /**
     * 异步get请求
     *
     * @param url      地址
     * @param callback Callback回调对象
     */
    public static void get(String url, Callback callback) {
        get(url, PARAMS, callback);
    }

    /**
     * 同步post请求
     *
     * @param url    地址
     * @param params 参数
     * @return http访问返回的结果
     */
    public static String post(String url, Map<String, Object> params) {
        return new String(postByte(url, params));
    }

    /**
     * 同步post请求
     *
     * @param url    地址
     * @param params 参数
     * @return http访问返回的结果
     */
    public static byte[] postByte(String url, Map<String, Object> params) {
        OkHttpClient okHttpClient = getOkHttpClient(url);
        RequestBody requestBody = getRequestBody(params);
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
        Call call = okHttpClient.newCall(request);
        return getResult(call);
    }

    /**
     * 同步post请求
     *
     * @param url 地址
     * @return http访问返回的结果
     */
    public static String post(String url) {
        return post(url, PARAMS);
    }

    /**
     * 同步post请求
     *
     * @param url 地址
     * @return http访问返回的结果
     */
    public static byte[] postByte(String url) {
        return postByte(url, PARAMS);
    }

    /**
     * 同步post请求
     *
     * @param url    地址
     * @param params 参数
     * @param clazz  反序列化的Class
     * @return http访问返回的如果是JSON数据则直接反序列化成该class的类
     */
    public static <T> T post(String url, Map<String, Object> params, Class<T> clazz) {
        return bodyToModel(url, clazz, post(url, params));
    }

    /**
     * 同步post请求
     *
     * @param url   地址
     * @param clazz 反序列化的Class
     * @return http访问返回的如果是JSON数据则直接反序列化成该class的类
     */
    public static <T> T post(String url, Class<T> clazz) {
        return post(url, PARAMS, clazz);
    }

    /**
     * 异步post请求
     *
     * @param url      地址
     * @param params   参数
     * @param callback Callback回调对象
     */
    public static void post(String url, Map<String, Object> params, Callback callback) {
        OkHttpClient okHttpClient = getOkHttpClient(url);
        RequestBody requestBody = getRequestBody(params);
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(callback);
    }

    /**
     * 异步post请求
     *
     * @param url      地址
     * @param callback Callback回调对象
     */
    public static void post(String url, Callback callback) {
        post(url, PARAMS, callback);
    }

}